/*
 * ! jQuery Form Plugin version: 3.51.0-2014.06.20 Requires jQuery v1.5 or later
 * Copyright (c) 2014 M. Alsup Examples and documentation at:
 * http://malsup.com/jquery/form/ Project repository:
 * https://github.com/malsup/form Dual licensed under the MIT and GPL licenses.
 * https://github.com/malsup/form#copyright-and-license
 */
/* global ActiveXObject */
// AMD support
(function(factory) {
    "use strict";
    if (typeof define === 'function' && define.amd) {
        // using AMD; register as anon module
        define(['jquery'], factory);
    } else {
        // no AMD; invoke directly
        factory((typeof(jQuery) != 'undefined') ? jQuery : window.Zepto);
    }
}(function($) {
    "use strict";
    /*
     * Usage Note: ----------- Do not use both ajaxSubmit and ajaxForm on the
     * same form. These functions are mutually exclusive. Use ajaxSubmit if you
     * want to bind your own submit handler to the form. For example,
     * $(document).ready(function() { $('#myForm').on('submit', function(e) {
     * e.preventDefault(); // <-- important $(this).ajaxSubmit({ target:
     * '#output' }); }); }); Use ajaxForm when you want the plugin to manage all
     * the event binding for you. For example, $(document).ready(function() {
     * $('#myForm').ajaxForm({ target: '#output' }); }); You can also use
     * ajaxForm with delegation (requires jQuery v1.7+), so the form does not
     * have to exist when you invoke ajaxForm: $('#myForm').ajaxForm({
     * delegation: true, target: '#output' }); When using ajaxForm, the
     * ajaxSubmit function will be invoked for you at the appropriate time.
     */
    /**
     * Feature detection
     */
    var feature = {};
    feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
    feature.formdata = window.FormData !== undefined;
    var hasProp = !!$.fn.prop;
    // attr2 uses prop when it can but checks the return type for
    // an expected string. this accounts for the case where a form
    // contains inputs with names like "action" or "method"; in those
    // cases "prop" returns the element
    $.fn.attr2 = function() {
        if (!hasProp) {
            return this.attr.apply(this, arguments);
        }
        var val = this.prop.apply(this, arguments);
        if ((val && val.jquery) || typeof val === 'string') {
            return val;
        }
        return this.attr.apply(this, arguments);
    };
    /**
     * ajaxSubmit() provides a mechanism for immediately submitting an HTML form
     * using AJAX.
     */
    $.fn.ajaxSubmit = function(options) {
        /* jshint scripturl:true */
        // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
        if (!this.length) {
            log('ajaxSubmit: skipping submit process - no element selected');
            return this;
        }
        var method, action, url, $form = this;
        if (typeof options == 'function') {
            options = {
                success : options
            };
        } else if (options === undefined) {
            options = {};
        }
        method = options.type || this.attr2('method');
        action = options.url || this.attr2('action');
        url = (typeof action === 'string') ? $.trim(action) : '';
        url = url || window.location.href || '';
        if (url) {
            // clean url (don't include hash vaue)
            url = (url.match(/^([^#]+)/) || [])[1];
        }
        options = $.extend(true, {
            url : url,
            success : $.ajaxSettings.success,
            type : method || $.ajaxSettings.type,
            iframeSrc : /^https/i.test(window.location.href || '')
                ? 'javascript:false'
                : 'about:blank'
        }, options);
        // hook for manipulating the form data before it is extracted;
        // convenient for use with rich editors like tinyMCE or FCKEditor
        var veto = {};
        this.trigger('form-pre-serialize', [this, options, veto]);
        if (veto.veto) {
            log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
            return this;
        }
        // provide opportunity to alter form data before it is serialized
        if (options.beforeSerialize
            && options.beforeSerialize(this, options) === false) {
            log('ajaxSubmit: submit aborted via beforeSerialize callback');
            return this;
        }
        var traditional = options.traditional;
        if (traditional === undefined) {
            traditional = $.ajaxSettings.traditional;
        }
        var elements = [];
        var qx, a = this.formToArray(options.semantic, elements);
        if (options.data) {
            options.extraData = options.data;
            qx = $.param(options.data, traditional);
        }
        // give pre-submit callback an opportunity to abort the submit
        if (options.beforeSubmit
            && options.beforeSubmit(a, this, options) === false) {
            log('ajaxSubmit: submit aborted via beforeSubmit callback');
            return this;
        }
        // fire vetoable 'validate' event
        this.trigger('form-submit-validate', [a, this, options, veto]);
        if (veto.veto) {
            log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
            return this;
        }
        var q = $.param(a, traditional);
        if (qx) {
            q = (q ? (q + '&' + qx) : qx);
        }
        if (options.type.toUpperCase() == 'GET') {
            options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
            options.data = null; // data is null for 'get'
        } else {
            options.data = q; // data is the query string for 'post'
        }
        var callbacks = [];
        if (options.resetForm) {
            callbacks.push(function() {
                $form.resetForm();
            });
        }
        if (options.clearForm) {
            callbacks.push(function() {
                $form.clearForm(options.includeHidden);
            });
        }
        // perform a load on the target only if dataType is not provided
        if (!options.dataType && options.target) {
            var oldSuccess = options.success || function() {
            };
            callbacks.push(function(data) {
                var fn = options.replaceTarget ? 'replaceWith' : 'html';
                $(options.target)[fn](data).each(oldSuccess, arguments);
            });
        } else if (options.success) {
            callbacks.push(options.success);
        }
        options.success = function(data, status, xhr) { // jQuery 1.4+ passes
            // xhr as 3rd arg
            var context = options.context || this; // jQuery 1.4+ supports
            // scope context
            for (var i = 0, max = callbacks.length; i < max; i++) {
                callbacks[i]
                    .apply(context, [data, status, xhr || $form, $form]);
            }
        };
        if (options.error) {
            var oldError = options.error;
            options.error = function(xhr, status, error) {
                var context = options.context || this;
                oldError.apply(context, [xhr, status, error, $form]);
            };
        }
        if (options.complete) {
            var oldComplete = options.complete;
            options.complete = function(xhr, status) {
                var context = options.context || this;
                oldComplete.apply(context, [xhr, status, $form]);
            };
        }
        // are there files to upload?
        // [value] (issue #113), also see comment:
        // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219
        var fileInputs = $('input[type=file]:enabled', this).filter(function() {
            return $(this).val() !== '';
        });
        var hasFileInputs = fileInputs.length > 0;
        var mp = 'multipart/form-data';
        var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
        var fileAPI = feature.fileapi && feature.formdata;
        log("fileAPI :" + fileAPI);
        var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
        var jqxhr;
        // options.iframe allows user to force iframe mode
        // 06-NOV-09: now defaulting to iframe mode if file input is detected
        if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
            // hack to fix Safari hang (thanks to Tim Molendijk for this)
            // see:
            // http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
            if (options.closeKeepAlive) {
                $.get(options.closeKeepAlive, function() {
                    jqxhr = fileUploadIframe(a);
                });
            } else {
                jqxhr = fileUploadIframe(a);
            }
        } else if ((hasFileInputs || multipart) && fileAPI) {
            jqxhr = fileUploadXhr(a);
        } else {
            jqxhr = $.ajax(options);
        }
        $form.removeData('jqxhr').data('jqxhr', jqxhr);
        // clear element array
        for (var k = 0; k < elements.length; k++) {
            elements[k] = null;
        }
        // fire 'notify' event
        this.trigger('form-submit-notify', [this, options]);
        return this;
        // utility fn for deep serialization
        function deepSerialize(extraData) {
            var serialized = $.param(extraData, options.traditional).split('&');
            var len = serialized.length;
            var result = [];
            var i, part;
            for (i = 0; i < len; i++) {
                // #252; undo param space replacement
                serialized[i] = serialized[i].replace(/\+/g, ' ');
                part = serialized[i].split('=');
                // #278; use array instead of object storage, favoring array
                // serializations
                result.push([decodeURIComponent(part[0]),
                    decodeURIComponent(part[1])]);
            }
            return result;
        }
        // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
        function fileUploadXhr(a) {
            var formdata = new FormData();
            for (var i = 0; i < a.length; i++) {
                formdata.append(a[i].name, a[i].value);
            }
            if (options.extraData) {
                var serializedData = deepSerialize(options.extraData);
                for (i = 0; i < serializedData.length; i++) {
                    if (serializedData[i]) {
                        formdata.append(serializedData[i][0],
                            serializedData[i][1]);
                    }
                }
            }
            options.data = null;
            var s = $.extend(true, {}, $.ajaxSettings, options, {
                contentType : false,
                processData : false,
                cache : false,
                type : method || 'POST'
            });
            if (options.uploadProgress) {
                // workaround because jqXHR does not expose upload property
                s.xhr = function() {
                    var xhr = $.ajaxSettings.xhr();
                    if (xhr.upload) {
                        xhr.upload.addEventListener('progress',
                            function(event) {
                                var percent = 0;
                                var position = event.loaded
                                    || event.position; /*
																 * event.position
																 * is deprecated
																 */
                                var total = event.total;
                                if (event.lengthComputable) {
                                    percent = Math.ceil(position / total
                                        * 100);
                                }
                                options.uploadProgress(event, position,
                                    total, percent);
                            }, false);
                    }
                    return xhr;
                };
            }
            s.data = null;
            var beforeSend = s.beforeSend;
            s.beforeSend = function(xhr, o) {
                // Send FormData() provided by user
                if (options.formData) {
                    o.data = options.formData;
                } else {
                    o.data = formdata;
                }
                if (beforeSend) {
                    beforeSend.call(this, xhr, o);
                }
            };
            return $.ajax(s);
        }
        // private function for handling file uploads (hat tip to YAHOO!)
        function fileUploadIframe(a) {
            var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
            var deferred = $.Deferred();
            // #341
            deferred.abort = function(status) {
                xhr.abort(status);
            };
            if (a) {
                // ensure that every serialized input is still enabled
                for (i = 0; i < elements.length; i++) {
                    el = $(elements[i]);
                    if (hasProp) {
                        el.prop('disabled', false);
                    } else {
                        el.removeAttr('disabled');
                    }
                }
            }
            s = $.extend(true, {}, $.ajaxSettings, options);
            s.context = s.context || s;
            id = 'jqFormIO' + (new Date().getTime());
            if (s.iframeTarget) {
                $io = $(s.iframeTarget);
                n = $io.attr2('name');
                if (!n) {
                    $io.attr2('name', id);
                } else {
                    id = n;
                }
            } else {
                $io = $('<iframe name="' + id + '" src="' + s.iframeSrc
                    + '" />');
                $io.css({
                    position : 'absolute',
                    top : '-1000px',
                    left : '-1000px'
                });
            }
            io = $io[0];
            xhr = { // mock object
                aborted : 0,
                responseText : null,
                responseXML : null,
                status : 0,
                statusText : 'n/a',
                getAllResponseHeaders : function() {
                },
                getResponseHeader : function() {
                },
                setRequestHeader : function() {
                },
                abort : function(status) {
                    var e = (status === 'timeout' ? 'timeout' : 'aborted');
                    log('aborting upload... ' + e);
                    this.aborted = 1;
                    try { // #214, #257
                        if (io.contentWindow.document.execCommand) {
                            io.contentWindow.document.execCommand('Stop');
                        }
                    } catch (ignore) {
                    }
                    $io.attr('src', s.iframeSrc); // abort op in progress
                    xhr.error = e;
                    if (s.error) {
                        s.error.call(s.context, xhr, e, status);
                    }
                    if (g) {
                        $.event.trigger("ajaxError", [xhr, s, e]);
                    }
                    if (s.complete) {
                        s.complete.call(s.context, xhr, e);
                    }
                }
            };
            g = s.global;
            // trigger ajax global events so that activity/block indicators work
            // like normal
            if (g && 0 === $.active++) {
                $.event.trigger("ajaxStart");
            }
            if (g) {
                $.event.trigger("ajaxSend", [xhr, s]);
            }
            if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
                if (s.global) {
                    $.active--;
                }
                deferred.reject();
                return deferred;
            }
            if (xhr.aborted) {
                deferred.reject();
                return deferred;
            }
            // add submitting element to data if we know it
            sub = form.clk;
            if (sub) {
                n = sub.name;
                if (n && !sub.disabled) {
                    s.extraData = s.extraData || {};
                    s.extraData[n] = sub.value;
                    if (sub.type == "image") {
                        s.extraData[n + '.x'] = form.clk_x;
                        s.extraData[n + '.y'] = form.clk_y;
                    }
                }
            }
            var CLIENT_TIMEOUT_ABORT = 1;
            var SERVER_ABORT = 2;
            function getDoc(frame) {
                /*
                 * it looks like contentWindow or contentDocument do not carry
                 * the protocol property in ie8, when running under ssl
                 * frame.document is the only valid response document, since the
                 * protocol is know but not on the other two objects. strange?
                 * "Same origin policy"
                 * http://en.wikipedia.org/wiki/Same_origin_policy
                 */
                var doc = null;
                // IE8 cascading access check
                try {
                    if (frame.contentWindow) {
                        doc = frame.contentWindow.document;
                    }
                } catch (err) {
                    // IE8 access denied under ssl & missing protocol
                    log('cannot get iframe.contentWindow document: ' + err);
                }
                if (doc) { // successful getting content
                    return doc;
                }
                try { // simply checking may throw in ie8 under ssl or
                    // mismatched protocol
                    doc = frame.contentDocument
                        ? frame.contentDocument
                        : frame.document;
                } catch (err) {
                    // last attempt
                    log('cannot get iframe.contentDocument: ' + err);
                    doc = frame.document;
                }
                return doc;
            }
            // Rails CSRF hack (thanks to Yvan Barthelemy)
            var csrf_token = $('meta[name=csrf-token]').attr('content');
            var csrf_param = $('meta[name=csrf-param]').attr('content');
            if (csrf_param && csrf_token) {
                s.extraData = s.extraData || {};
                s.extraData[csrf_param] = csrf_token;
            }
            // take a breath so that pending repaints get some cpu time before
            // the upload starts
            function doSubmit() {
                // make sure form attrs are set
                var t = $form.attr2('target'), a = $form.attr2('action'), mp = 'multipart/form-data', et = $form
                        .attr('enctype')
                    || $form.attr('encoding') || mp;
                // update form attrs in IE friendly way
                form.setAttribute('target', id);
                if (!method || /post/i.test(method)) {
                    form.setAttribute('method', 'POST');
                }
                if (a != s.url) {
                    form.setAttribute('action', s.url);
                }
                // ie borks in some cases when setting encoding
                if (!s.skipEncodingOverride
                    && (!method || /post/i.test(method))) {
                    $form.attr({
                        encoding : 'multipart/form-data',
                        enctype : 'multipart/form-data'
                    });
                }
                // support timout
                if (s.timeout) {
                    timeoutHandle = setTimeout(function() {
                        timedOut = true;
                        cb(CLIENT_TIMEOUT_ABORT);
                    }, s.timeout);
                }
                // look for server aborts
                function checkState() {
                    try {
                        var state = getDoc(io).readyState;
                        log('state = ' + state);
                        if (state && state.toLowerCase() == 'uninitialized') {
                            setTimeout(checkState, 50);
                        }
                    } catch (e) {
                        log('Server abort: ', e, ' (', e.name, ')');
                        cb(SERVER_ABORT);
                        if (timeoutHandle) {
                            clearTimeout(timeoutHandle);
                        }
                        timeoutHandle = undefined;
                    }
                }
                // add "extra" data to form if provided in options
                var extraInputs = [];
                try {
                    if (s.extraData) {
                        for (var n in s.extraData) {
                            if (s.extraData.hasOwnProperty(n)) {
                                // if using the $.param format that allows for
                                // multiple values with the same name
                                if ($.isPlainObject(s.extraData[n])
                                    && s.extraData[n]
                                        .hasOwnProperty('name')
                                    && s.extraData[n]
                                        .hasOwnProperty('value')) {
                                    extraInputs
                                        .push(	$('<input type="hidden" name="'
                                            + s.extraData[n].name
                                            + '">')
                                            .val(s.extraData[n].value)
                                            .appendTo(form)[0]);
                                } else {
                                    extraInputs
                                        .push(	$('<input type="hidden" name="'
                                            + n + '">')
                                            .val(s.extraData[n])
                                            .appendTo(form)[0]);
                                }
                            }
                        }
                    }
                    if (!s.iframeTarget) {
                        // add iframe to doc and submit the form
                        $io.appendTo('body');
                    }
                    if (io.attachEvent) {
                        io.attachEvent('onload', cb);
                    } else {
                        io.addEventListener('load', cb, false);
                    }
                    setTimeout(checkState, 15);
                    try {
                        form.submit();
                    } catch (err) {
                        // just in case form has element with name/id of
                        // 'submit'
                        var submitFn = document.createElement('form').submit;
                        submitFn.apply(form);
                    }
                } finally {
                    // reset attrs and remove "extra" input elements
                    form.setAttribute('action', a);
                    form.setAttribute('enctype', et); // #380
                    if (t) {
                        form.setAttribute('target', t);
                    } else {
                        $form.removeAttr('target');
                    }
                    $(extraInputs).remove();
                }
            }
            if (s.forceSync) {
                doSubmit();
            } else {
                setTimeout(doSubmit, 10); // this lets dom updates render
            }
            var data, doc, domCheckCount = 50, callbackProcessed;
            function cb(e) {
                if (xhr.aborted || callbackProcessed) {
                    return;
                }
                doc = getDoc(io);
                if (!doc) {
                    log('cannot access response document');
                    e = SERVER_ABORT;
                }
                if (e === CLIENT_TIMEOUT_ABORT && xhr) {
                    xhr.abort('timeout');
                    deferred.reject(xhr, 'timeout');
                    return;
                } else if (e == SERVER_ABORT && xhr) {
                    xhr.abort('server abort');
                    deferred.reject(xhr, 'error', 'server abort');
                    return;
                }
                if (!doc || doc.location.href == s.iframeSrc) {
                    // response not received yet
                    if (!timedOut) {
                        return;
                    }
                }
                if (io.detachEvent) {
                    io.detachEvent('onload', cb);
                } else {
                    io.removeEventListener('load', cb, false);
                }
                var status = 'success', errMsg;
                try {
                    if (timedOut) {
                        throw 'timeout';
                    }
                    var isXml = s.dataType == 'xml' || doc.XMLDocument
                        || $.isXMLDoc(doc);
                    log('isXml=' + isXml);
                    if (!isXml && window.opera
                        && (doc.body === null || !doc.body.innerHTML)) {
                        if (--domCheckCount) {
                            // in some browsers (Opera) the iframe DOM is not
                            // always traversable when
                            // the onload callback fires, so we loop a bit to
                            // accommodate
                            log('requeing onLoad callback, DOM not available');
                            setTimeout(cb, 250);
                            return;
                        }
                        // let this fall through because server response could
                        // be an empty document
                        // log('Could not access iframe DOM after mutiple
                        // tries.');
                        // throw 'DOMException: not available';
                    }
                    // log('response detected');
                    var docRoot = doc.body ? doc.body : doc.documentElement;
                    xhr.responseText = docRoot ? docRoot.innerHTML : null;
                    xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
                    if (isXml) {
                        s.dataType = 'xml';
                    }
                    xhr.getResponseHeader = function(header) {
                        var headers = {
                            'content-type' : s.dataType
                        };
                        return headers[header.toLowerCase()];
                    };
                    // support for XHR 'status' & 'statusText' emulation :
                    if (docRoot) {
                        xhr.status = Number(docRoot.getAttribute('status'))
                            || xhr.status;
                        xhr.statusText = docRoot.getAttribute('statusText')
                            || xhr.statusText;
                    }
                    var dt = (s.dataType || '').toLowerCase();
                    var scr = /(json|script|text)/.test(dt);
                    if (scr || s.textarea) {
                        // see if user embedded response in textarea
                        var ta = doc.getElementsByTagName('textarea')[0];
                        if (ta) {
                            xhr.responseText = ta.value;
                            // support for XHR 'status' & 'statusText' emulation
                            // :
                            xhr.status = Number(ta.getAttribute('status'))
                                || xhr.status;
                            xhr.statusText = ta.getAttribute('statusText')
                                || xhr.statusText;
                        } else if (scr) {
                            // account for browsers injecting pre around json
                            // response
                            var pre = doc.getElementsByTagName('pre')[0];
                            var b = doc.getElementsByTagName('body')[0];
                            if (pre) {
                                xhr.responseText = pre.textContent
                                    ? pre.textContent
                                    : pre.innerText;
                            } else if (b) {
                                xhr.responseText = b.textContent
                                    ? b.textContent
                                    : b.innerText;
                            }
                        }
                    } else if (dt == 'xml' && !xhr.responseXML
                        && xhr.responseText) {
                        xhr.responseXML = toXml(xhr.responseText);
                    }
                    try {
                        data = httpData(xhr, dt, s);
                    } catch (err) {
                        status = 'parsererror';
                        xhr.error = errMsg = (err || status);
                    }
                } catch (err) {
                    log('error caught: ', err);
                    status = 'error';
                    xhr.error = errMsg = (err || status);
                }
                if (xhr.aborted) {
                    log('upload aborted');
                    status = null;
                }
                if (xhr.status) { // we've set xhr.status
                    status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)
                        ? 'success'
                        : 'error';
                }
                // ordering of these callbacks/triggers is odd, but that's how
                // $.ajax does it
                if (status === 'success') {
                    if (s.success) {
                        s.success.call(s.context, data, 'success', xhr);
                    }
                    deferred.resolve(xhr.responseText, 'success', xhr);
                    if (g) {
                        $.event.trigger("ajaxSuccess", [xhr, s]);
                    }
                } else if (status) {
                    if (errMsg === undefined) {
                        errMsg = xhr.statusText;
                    }
                    if (s.error) {
                        s.error.call(s.context, xhr, status, errMsg);
                    }
                    deferred.reject(xhr, 'error', errMsg);
                    if (g) {
                        $.event.trigger("ajaxError", [xhr, s, errMsg]);
                    }
                }
                if (g) {
                    $.event.trigger("ajaxComplete", [xhr, s]);
                }
                if (g && !--$.active) {
                    $.event.trigger("ajaxStop");
                }
                if (s.complete) {
                    s.complete.call(s.context, xhr, status);
                }
                callbackProcessed = true;
                if (s.timeout) {
                    clearTimeout(timeoutHandle);
                }
                // clean up
                setTimeout(function() {
                    if (!s.iframeTarget) {
                        $io.remove();
                    } else { // adding else to clean up existing
                        // iframe response.
                        $io.attr('src', s.iframeSrc);
                    }
                    xhr.responseXML = null;
                }, 100);
            }
            var toXml = $.parseXML || function(s, doc) { // use parseXML if
                // available (jQuery
                // 1.5+)
                if (window.ActiveXObject) {
                    doc = new ActiveXObject('Microsoft.XMLDOM');
                    doc.async = 'false';
                    doc.loadXML(s);
                } else {
                    doc = (new DOMParser()).parseFromString(s,
                        'text/xml');
                }
                return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror')
                    ? doc
                    : null;
            };
            var parseJSON = $.parseJSON || function(s) {
                /* jslint evil:true */
                return window['eval']('(' + s + ')');
            };
            var httpData = function(xhr, type, s) { // mostly lifted from
                // jq1.4.4
                var ct = xhr.getResponseHeader('content-type') || '', xml = type === 'xml'
                    || !type && ct.indexOf('xml') >= 0, data = xml
                    ? xhr.responseXML
                    : xhr.responseText;
                if (xml && data.documentElement.nodeName === 'parsererror') {
                    if ($.error) {
                        $.error('parsererror');
                    }
                }
                if (s && s.dataFilter) {
                    data = s.dataFilter(data, type);
                }
                if (typeof data === 'string') {
                    if (type === 'json' || !type && ct.indexOf('json') >= 0) {
                        data = parseJSON(data);
                    } else if (type === "script" || !type
                        && ct.indexOf("javascript") >= 0) {
                        $.globalEval(data);
                    }
                }
                return data;
            };
            return deferred;
        }
    };
    /**
     * ajaxForm() provides a mechanism for fully automating form submission.
     *
     * The advantages of using this method instead of ajaxSubmit() are:
     *
     * 1: This method will include coordinates for <input type="image" />
     * elements (if the element is used to submit the form). 2. This method will
     * include the submit element's name/value data (for the element that was
     * used to submit the form). 3. This method binds the submit() method to the
     * form for you.
     *
     * The options argument for ajaxForm works exactly as it does for
     * ajaxSubmit. ajaxForm merely passes the options argument along after
     * properly binding events for submit elements and the form itself.
     */
    $.fn.ajaxForm = function(options) {
        options = options || {};
        options.delegation = options.delegation && $.isFunction($.fn.on);
        // in jQuery 1.3+ we can fix mistakes with the ready state
        if (!options.delegation && this.length === 0) {
            var o = {
                s : this.selector,
                c : this.context
            };
            if (!$.isReady && o.s) {
                log('DOM not ready, queuing ajaxForm');
                $(function() {
                    $(o.s, o.c).ajaxForm(options);
                });
                return this;
            }
            // is your DOM ready?
            // http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
            log('terminating; zero elements found by selector'
                + ($.isReady ? '' : ' (DOM not ready)'));
            return this;
        }
        if (options.delegation) {
            $(document).off('submit.form-plugin', this.selector, doAjaxSubmit)
                .off('click.form-plugin', this.selector,
                    captureSubmittingElement).on('submit.form-plugin',
                this.selector, options, doAjaxSubmit).on(
                'click.form-plugin', this.selector, options,
                captureSubmittingElement);
            return this;
        }
        return this.ajaxFormUnbind().bind('submit.form-plugin', options,
            doAjaxSubmit).bind('click.form-plugin', options,
            captureSubmittingElement);
    };
    // private event handlers
    function doAjaxSubmit(e) {
        /* jshint validthis:true */
        var options = e.data;
        if (!e.isDefaultPrevented()) { // if event has been canceled, don't
            // proceed
            e.preventDefault();
            $(e.target).ajaxSubmit(options); // #365
        }
    }
    function captureSubmittingElement(e) {
        /* jshint validthis:true */
        var target = e.target;
        var $el = $(target);
        if (!($el.is("[type=submit],[type=image]"))) {
            // is this a child element of the submit el? (ex: a span within a
            // button)
            var t = $el.closest('[type=submit]');
            if (t.length === 0) {
                return;
            }
            target = t[0];
        }
        var form = this;
        form.clk = target;
        if (target.type == 'image') {
            if (e.offsetX !== undefined) {
                form.clk_x = e.offsetX;
                form.clk_y = e.offsetY;
            } else if (typeof $.fn.offset == 'function') {
                var offset = $el.offset();
                form.clk_x = e.pageX - offset.left;
                form.clk_y = e.pageY - offset.top;
            } else {
                form.clk_x = e.pageX - target.offsetLeft;
                form.clk_y = e.pageY - target.offsetTop;
            }
        }
        // clear form vars
        setTimeout(function() {
            form.clk = form.clk_x = form.clk_y = null;
        }, 100);
    }
    // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
    $.fn.ajaxFormUnbind = function() {
        return this.unbind('submit.form-plugin click.form-plugin');
    };
    /**
     * formToArray() gathers form element data into an array of objects that can
     * be passed to any of the following ajax functions: $.get, $.post, or load.
     * Each object in the array has both a 'name' and 'value' property. An
     * example of an array for a simple login form might be:
     *  [ { name: 'username', value: 'jresig' }, { name: 'password', value:
     * 'secret' } ]
     *
     * It is this array that is passed to pre-submit callback functions provided
     * to the ajaxSubmit() and ajaxForm() methods.
     */
    $.fn.formToArray = function(semantic, elements) {
        var a = [];
        if (this.length === 0) {
            return a;
        }
        var form = this[0];
        var formId = this.attr('id');
        var els = semantic ? form.getElementsByTagName('*') : form.elements;
        var els2;
        if (els && !/MSIE [678]/.test(navigator.userAgent)) { // #390
            els = $(els).get(); // convert to standard array
        }
        // #386; account for inputs outside the form which use the 'form'
        // attribute
        if (formId) {
            els2 = $(':input[form="' + formId + '"]').get(); // hat tip @thet
            if (els2.length) {
                els = (els || []).concat(els2);
            }
        }
        if (!els || !els.length) {
            return a;
        }
        var i, j, n, v, el, max, jmax;
        for (i = 0, max = els.length; i < max; i++) {
            el = els[i];
            n = el.name;
            if (!n || el.disabled) {
                continue;
            }
            if (semantic && form.clk && el.type == "image") {
                // handle image inputs on the fly when semantic == true
                if (form.clk == el) {
                    a.push({
                        name : n,
                        value : $(el).val(),
                        type : el.type
                    });
                    a.push({
                        name : n + '.x',
                        value : form.clk_x
                    }, {
                        name : n + '.y',
                        value : form.clk_y
                    });
                }
                continue;
            }
            v = $.fieldValue(el, true);
            if (v && v.constructor == Array) {
                if (elements) {
                    elements.push(el);
                }
                for (j = 0, jmax = v.length; j < jmax; j++) {
                    a.push({
                        name : n,
                        value : v[j]
                    });
                }
            } else if (feature.fileapi && el.type == 'file') {
                if (elements) {
                    elements.push(el);
                }
                var files = el.files;
                if (files.length) {
                    for (j = 0; j < files.length; j++) {
                        a.push({
                            name : n,
                            value : files[j],
                            type : el.type
                        });
                    }
                } else {
                    // #180
                    a.push({
                        name : n,
                        value : '',
                        type : el.type
                    });
                }
            } else if (v !== null && typeof v != 'undefined') {
                if (elements) {
                    elements.push(el);
                }
                a.push({
                    name : n,
                    value : v,
                    type : el.type,
                    required : el.required
                });
            }
        }
        if (!semantic && form.clk) {
            // input type=='image' are not found in elements array! handle it
            // here
            var $input = $(form.clk), input = $input[0];
            n = input.name;
            if (n && !input.disabled && input.type == 'image') {
                a.push({
                    name : n,
                    value : $input.val()
                });
                a.push({
                    name : n + '.x',
                    value : form.clk_x
                }, {
                    name : n + '.y',
                    value : form.clk_y
                });
            }
        }
        return a;
    };
    /**
     * Serializes form data into a 'submittable' string. This method will return
     * a string in the format: name1=value1&amp;name2=value2
     */
    $.fn.formSerialize = function(semantic) {
        // hand off to jQuery.param for proper encoding
        return $.param(this.formToArray(semantic));
    };
    /**
     * Serializes all field elements in the jQuery object into a query string.
     * This method will return a string in the format:
     * name1=value1&amp;name2=value2
     */
    $.fn.fieldSerialize = function(successful) {
        var a = [];
        this.each(function() {
            var n = this.name;
            if (!n) {
                return;
            }
            var v = $.fieldValue(this, successful);
            if (v && v.constructor == Array) {
                for (var i = 0, max = v.length; i < max; i++) {
                    a.push({
                        name : n,
                        value : v[i]
                    });
                }
            } else if (v !== null && typeof v != 'undefined') {
                a.push({
                    name : this.name,
                    value : v
                });
            }
        });
        // hand off to jQuery.param for proper encoding
        return $.param(a);
    };
    /**
     * Returns the value(s) of the element in the matched set. For example,
     * consider the following form:
     *
     * <form><fieldset> <input name="A" type="text" /> <input name="A"
     * type="text" /> <input name="B" type="checkbox" value="B1" /> <input
     * name="B" type="checkbox" value="B2"/> <input name="C" type="radio"
     * value="C1" /> <input name="C" type="radio" value="C2" /> </fieldset></form>
     *
     * var v = $('input[type=text]').fieldValue(); // if no values are entered
     * into the text inputs v == ['',''] // if values entered into the text
     * inputs are 'foo' and 'bar' v == ['foo','bar']
     *
     * var v = $('input[type=checkbox]').fieldValue(); // if neither checkbox is
     * checked v === undefined // if both checkboxes are checked v == ['B1',
     * 'B2']
     *
     * var v = $('input[type=radio]').fieldValue(); // if neither radio is
     * checked v === undefined // if first radio is checked v == ['C1']
     *
     * The successful argument controls whether or not the field element must be
     * 'successful' (per
     * http://www.w3.org/TR/html4/interact/forms.html#successful-controls). The
     * default value of the successful argument is true. If this value is false
     * the value(s) for each element is returned.
     *
     * Note: This method *always* returns an array. If no valid value can be
     * determined the array will be empty, otherwise it will contain one or more
     * values.
     */
    $.fn.fieldValue = function(successful) {
        for (var val = [], i = 0, max = this.length; i < max; i++) {
            var el = this[i];
            var v = $.fieldValue(el, successful);
            if (v === null || typeof v == 'undefined'
                || (v.constructor == Array && !v.length)) {
                continue;
            }
            if (v.constructor == Array) {
                $.merge(val, v);
            } else {
                val.push(v);
            }
        }
        return val;
    };
    /**
     * Returns the value of the field element.
     */
    $.fieldValue = function(el, successful) {
        var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
        if (successful === undefined) {
            successful = true;
        }
        if (successful
            && (!n || el.disabled || t == 'reset' || t == 'button'
                || (t == 'checkbox' || t == 'radio') && !el.checked
                || (t == 'submit' || t == 'image') && el.form
                && el.form.clk != el || tag == 'select'
                && el.selectedIndex == -1)) {
            return null;
        }
        if (tag == 'select') {
            var index = el.selectedIndex;
            if (index < 0) {
                return null;
            }
            var a = [], ops = el.options;
            var one = (t == 'select-one');
            var max = (one ? index + 1 : ops.length);
            for (var i = (one ? index : 0); i < max; i++) {
                var op = ops[i];
                if (op.selected) {
                    var v = op.value;
                    if (!v) { // extra pain for IE...
                        v = (op.attributes && op.attributes.value && !(op.attributes.value.specified))
                            ? op.text
                            : op.value;
                    }
                    if (one) {
                        return v;
                    }
                    a.push(v);
                }
            }
            return a;
        }
        return $(el).val();
    };
    /**
     * Clears the form data. Takes the following actions on the form's input
     * fields: - input text fields will have their 'value' property set to the
     * empty string - select elements will have their 'selectedIndex' property
     * set to -1 - checkbox and radio inputs will have their 'checked' property
     * set to false - inputs of type submit, button, reset, and hidden will
     * *not* be effected - button elements will *not* be effected
     */
    $.fn.clearForm = function(includeHidden) {
        return this.each(function() {
            $('input,select,textarea', this).clearFields(includeHidden);
        });
    };
    /**
     * Clears the selected form elements.
     */
    $.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
        var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden'
        // is
        // not
        // in
        // this
        // list
        return this.each(function() {
            var t = this.type, tag = this.tagName.toLowerCase();
            if (re.test(t) || tag == 'textarea') {
                this.value = '';
            } else if (t == 'checkbox' || t == 'radio') {
                this.checked = false;
            } else if (tag == 'select') {
                this.selectedIndex = -1;
            } else if (t == "file") {
                if (/MSIE/.test(navigator.userAgent)) {
                    $(this).replaceWith($(this).clone(true));
                } else {
                    $(this).val('');
                }
            } else if (includeHidden) {
                // includeHidden can be the value true, or it can be a
                // selector string
                // indicating a special test; for example:
                // $('#myForm').clearForm('.special:hidden')
                // the above would clean hidden inputs that have the
                // class of 'special'
                if ((includeHidden === true && /hidden/.test(t))
                    || (typeof includeHidden == 'string' && $(this)
                        .is(includeHidden))) {
                    this.value = '';
                }
            }
        });
    };
    /**
     * Resets the form data. Causes all form elements to be reset to their
     * original value.
     */
    $.fn.resetForm = function() {
        return this.each(function() {
            // guard against an input with the name of 'reset'
            // note that IE reports the reset function as an 'object'
            if (typeof this.reset == 'function'
                || (typeof this.reset == 'object' && !this.reset.nodeType)) {
                this.reset();
            }
        });
    };
    /**
     * Enables or disables any matching elements.
     */
    $.fn.enable = function(b) {
        if (b === undefined) {
            b = true;
        }
        return this.each(function() {
            this.disabled = !b;
        });
    };
    /**
     * Checks/unchecks any matching checkboxes or radio buttons and
     * selects/deselects and matching option elements.
     */
    $.fn.selected = function(select) {
        if (select === undefined) {
            select = true;
        }
        return this.each(function() {
            var t = this.type;
            if (t == 'checkbox' || t == 'radio') {
                this.checked = select;
            } else if (this.tagName.toLowerCase() == 'option') {
                var $sel = $(this).parent('select');
                if (select && $sel[0] && $sel[0].type == 'select-one') {
                    // deselect all other options
                    $sel.find('option').selected(false);
                }
                this.selected = select;
            }
        });
    };
    // expose debug var
    $.fn.ajaxSubmit.debug = false;
    // helper fn for console logging
    function log() {
        if (!$.fn.ajaxSubmit.debug) {
            return;
        }
        var msg = '[jquery.form] ' + Array.prototype.join.call(arguments, '');
        if (window.console && window.console.log) {
            window.console.log(msg);
        } else if (window.opera && window.opera.postError) {
            window.opera.postError(msg);
        }
    }
}));